PythonでCron式から実行日付を取得する

PythonでCron式から実行日付を取得する

Clock Icon2024.04.22

はじめに

データアナリティクス事業本部のkobayashiです。

pythonでCron形式のスケジュール式から実際の実行時刻を計算する必要がありなにか良いパッケージはないかと探していたところピッタリなパッケージがあったので使ってみたいと思います。またAmazon EventBridgeのAWSサービスで使われるCron形式は一般的なCron形式を扱うcroniterでは計算できないのでこちらはpyawscronのパッケージを使ってみたいと思います。

Cron形式から実行時間を計算してみる

環境

  • Python: 3.11.4
  • croniter: 2.0.5
  • pyawscron: 1.0.6

それではcroniterとpyawscronでCron形式から実行時間を計算してみたいと思います。

croniterを使って一般的なCron形式を扱う

はじめに一般的なCron形式を扱うcroniterで実行時間を計算してみます。

インストールはいつも通りのpipを使います。

pip install croniter

では早速croniterを使ってみます。 実行するのは下記のコードになります。

from croniter import croniter
from datetime import datetime, timezone

cron_expression_1 = "0 10 * * *"  # 毎日午前 10:00に実行
cron_expression_2 = "15 12 * * *"  # 毎日午後 12:15に実行
cron_expression_3 = "0 18 * * MON-FRI"  # 毎週月曜日から金曜日まで午後 6:00に実行
cron_expression_4 = "0 8 1 * *"  # 毎月 1 日の午前 8:00に実行
cron_expression_5 = "0/15 * * * *"  # 15 分ごとに実行

# 基準日を設定
base_dt = datetime(2024, 4, 1, 10, 1, tzinfo=timezone.utc)

# 次の実行時間を計算
print("毎日午前 10:00に実行")
iter = croniter(cron_expression_1, base_dt)
for _i in range(3):
    dt = iter.get_next(datetime)
    print(dt)

print("毎日午後 12:15に実行")
iter = croniter(cron_expression_2, base_dt)
for _i in range(3):
    dt = iter.get_next(datetime)
    print(dt)

print("毎週月曜日から金曜日まで午後 6:00に実行")
iter = croniter(cron_expression_3, base_dt)
for _i in range(6):
    dt = iter.get_next(datetime)
    print(dt)

print("毎月 1 日の午前 8:00に実行")
iter = croniter(cron_expression_4, base_dt)
for _i in range(3):
    dt = iter.get_next(datetime)
    print(dt)

print("15 分ごとに実行")
iter = croniter(cron_expression_5, base_dt)
for _i in range(3):
    dt = iter.get_next(datetime)
    print(dt)

croniterを使う際に必要なパラメータはCron式と基準時間の2つです。

from croniter import croniterでcroniterをインポートした上でcroniter()でイテレータを生成してから実行時間を計算します。上記のスクリプトを実行すると以下のような結果が得られ想定通りCron形式から実行時間を計算できました。

毎日午前 10:00に実行
2024-04-02 10:00:00+00:00
2024-04-03 10:00:00+00:00
2024-04-04 10:00:00+00:00

毎日午後 12:15に実行
2024-04-01 12:15:00+00:00
2024-04-02 12:15:00+00:00
2024-04-03 12:15:00+00:00

毎週月曜日から金曜日まで午後 6:00に実行
2024-04-01 18:00:00+00:00
2024-04-02 18:00:00+00:00
2024-04-03 18:00:00+00:00
2024-04-04 18:00:00+00:00
2024-04-05 18:00:00+00:00
2024-04-08 18:00:00+00:00

毎月 1 日の午前 8:00に実行
2024-05-01 08:00:00+00:00
2024-06-01 08:00:00+00:00
2024-07-01 08:00:00+00:00

15 分ごとに実行
2024-04-01 10:15:00+00:00
2024-04-01 10:30:00+00:00
2024-04-01 10:45:00+00:00

croniterは次の実行時間だけではなく前の実行時間も計算できます。

from croniter import croniter
from datetime import datetime, timezone

cron_expression_1 = "0 10 * * *"  # 毎日午前 10:00に実行

# 基準日を設定
base_dt = datetime(2024, 4, 1, 10, 1, tzinfo=timezone.utc)

# 前の実行時間を計算
print("毎日午前 10:00に実行")
iter = croniter(cron_expression_1, base_dt)
for _i in range(3):
    dt = iter.get_prev(datetime)
    print(dt)

次の実行時間はget_nextで取得していましたが前の実行時間はget_prevで取得できます。

毎日午前 10:00に実行
2024-04-01 10:00:00+00:00
2024-03-31 10:00:00+00:00
2024-03-30 10:00:00+00:00

croniterには実行時間の計算だけでなくcroniter.matchを使うことでCron式の検算を行うこともできます。

croniter.match("0 10 * * *", datetime(2024, 4, 1, 10, 1, tzinfo=timezone.utc))
> False

croniter.match("0 10 * * *", datetime(2024, 4, 1, 10, 0, tzinfo=timezone.utc))
> True

pyawscronを使ってAWSのCron形式を扱う

次にAWSのCron形式を扱うpyawscronで実行時間を計算してみます。

インストールはこちらもいつも通りのpipを使います。

pip install pyawscron

ではpyawscronを使ってみます。 実行するのは下記のコードになります。

from pyawscron import AWSCron
from datetime import datetime, timezone

cron_expression_1 = "0 10 * * ? *"  # 毎日午前 10:00に実行
cron_expression_2 = "15 12 * * ? *"  # 毎日午後 12:15に実行
cron_expression_3 = "0 18 ? * MON-FRI *"  # 毎週月曜日から金曜日まで午後 6:00に実行
cron_expression_4 = "0 8 1 * ? *"  # 毎月 1 日の午前 8:00に実行
cron_expression_5 = "0/15 * * * ? *"  # 15 分ごとに実行

# 基準日を設定
base_dt = datetime(2024, 4, 1, 10, 1, tzinfo=timezone.utc)

# 次の実行時間を計算
print("毎日午前 10:00に実行")
aws_cron = AWSCron(cron_expression_1)
dt = base_dt
for _i in range(3):
    dt = aws_cron.occurrence(dt).next()
    print(dt)

print("毎日午後 12:15に実行")
aws_cron = AWSCron(cron_expression_2)
dt = base_dt
for _i in range(3):
    dt = aws_cron.occurrence(dt).next()
    print(dt)

print("毎週月曜日から金曜日まで午後 6:00に実行")
aws_cron = AWSCron(cron_expression_3)
dt = base_dt
for _i in range(6):
    dt = aws_cron.occurrence(dt).next()
    print(dt)

print("毎月 1 日の午前 8:00に実行")
aws_cron = AWSCron(cron_expression_4)
dt = base_dt
for _i in range(3):
    dt = aws_cron.occurrence(dt).next()
    print(dt)

print("15 分ごとに実行")
aws_cron = AWSCron(cron_expression_5)
dt = base_dt
for _i in range(3):
    dt = aws_cron.occurrence(dt).next()
    print(dt)

pyawscronを使う際に必要なパラメータもcroniterと同様にCron式と基準時間の2つです。

from pyawscron import AWSCronでAWSCronをインポートしてからAWSCron()でインスタンスを作成してからnext()メソッドで実行時間を取得します。

上記のスクリプトを実行するとcroniterと同じ結果が得られ想定通りCron形式から実行時間を計算できました。

毎日午前 10:00に実行
2024-04-02 10:00:00+00:00
2024-04-03 10:00:00+00:00
2024-04-04 10:00:00+00:00

毎日午後 12:15に実行
2024-04-01 12:15:00+00:00
2024-04-02 12:15:00+00:00
2024-04-03 12:15:00+00:00

毎週月曜日から金曜日まで午後 6:00に実行
2024-04-01 18:00:00+00:00
2024-04-02 18:00:00+00:00
2024-04-03 18:00:00+00:00
2024-04-04 18:00:00+00:00
2024-04-05 18:00:00+00:00
2024-04-08 18:00:00+00:00

毎月 1 日の午前 8:00に実行
2024-05-01 08:00:00+00:00
2024-06-01 08:00:00+00:00
2024-07-01 08:00:00+00:00

15 分ごとに実行
2024-04-01 10:15:00+00:00
2024-04-01 10:30:00+00:00
2024-04-01 10:45:00+00:00

pyawscronはcroniterと同じようには次の実行時間だけではなく前の実行時間も計算できます。

from pyawscron import AWSCron
from datetime import datetime, timezone

cron_expression_1 = "0 10 * * ? *"  # 毎日午前 10:00に実行

# 基準日を設定
base_dt = datetime(2024, 4, 1, 10, 1, tzinfo=timezone.utc)

# 前の実行時間を計算
print("毎日午前 10:00に実行")
aws_cron = AWSCron(cron_expression_1)
dt = base_dt
for _i in range(3):
    dt = aws_cron.occurrence(dt).prev()
    print(dt)

pyawscronでは次の実行時間はnext()で取得していましたが前の実行時間はprev()で取得できます。

毎日午前 10:00に実行
2024-04-01 10:00:00+00:00
2024-03-31 10:00:00+00:00
2024-03-30 10:00:00+00:00

まとめ

pythonでCron形式のスケジュール式から実際の実行時刻を計算するcroniterのパッケージ使って実行時間を取得できることを試してみました。またAmazon EventBridgeのAWSサービスで使われるCron形式ではpyawscronのパッケージを使って実行時間を取得してみました。使う場面はあまり多くないと思いますがどちらも簡単に実行時間が取得できました。

最後まで読んで頂いてありがとうございました。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.